package com.dg.dgrmi.net;

import java.io.IOException;
import java.lang.reflect.Proxy;
import java.nio.BufferUnderflowException;
import java.nio.channels.ClosedChannelException;
import java.util.LinkedList;
import java.util.List;

import com.dg.dgrmi.handler.*;
import com.dg.dgrmi.handler.filter.DefaultFilter;
import com.dg.dgrmi.handler.filter.IProtocolFilter;
import org.xsocket.MaxReadSizeExceededException;
import org.xsocket.connection.*;


/**
 * The LipeRMI client.
 * Connects to a LipeRMI Server in a address:port
 * and create local dynamic proxys to call remote
 * methods through a simple interface.
 *
 * @author lipe
 * @date   05/10/2006
 *
 * @see    net.sf.lipermi.handler.CallHandler
 * @see    net.sf.lipermi.net.Server
 */
public class DGRMIClient implements IDataHandler {

    private INonBlockingConnection socket;

    private ConnectionHandler connectionHandler;

    private final IConnectionHandlerListener connectionHandlerListener = new
            IConnectionHandlerListener() {
        public void connectionClosed() {
            for (IDGRMIClientListener listener : listeners) {
                listener.disconnected();
            }
        }
    };

    private List<IDGRMIClientListener> listeners = new LinkedList<
            IDGRMIClientListener>();

    public void addClientListener(IDGRMIClientListener listener) {
        listeners.add(listener);
    }

    public void removeClientListener(IDGRMIClientListener listener) {
        listeners.remove(listener);
    }

    public DGRMIClient(String address, int port, CallHandler callHandler) throws
            IOException {
        this(address, port, callHandler, new DefaultFilter());
    }

    public DGRMIClient(String address, int port, CallHandler callHandler,
                       IProtocolFilter filter) throws IOException {
        socket = new NonBlockingConnection(address, port, this);
        connectionHandler = ConnectionHandler.createConnectionHandler(socket,
                callHandler, filter, connectionHandlerListener);
    }

    public void close() throws IOException {
        socket.close();
    }

    public Object getGlobal(Class<?> clazz) {
        return Proxy.newProxyInstance(clazz.getClassLoader(),
                                      new Class[] {clazz},
                                      new CallProxy(connectionHandler));
    }

    public boolean onData(INonBlockingConnection connection) throws
            BufferUnderflowException, IOException, ClosedChannelException,
            MaxReadSizeExceededException {
        connectionHandler.messageResieved();
        return false;
    }
}
